<?php

namespace Api\Controller;

use Think\Controller;

require_once('vendor/autoload.php');

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

class WxpayController extends Controller
{

    // 商户号
    public $merchantId = '1651293484';
    // 商户API私钥
    public $merchantPrivateKeyFilePath = 'file://wechatpay/apiclient_key.pem';
    // 「商户API证书」的「证书序列号」
    public $merchantCertificateSerial = '48642094298CF56ED5EAFB67B40EE2C24F6D0540';
    // 微信支付平台证书
    public $platformCertificateFilePath = 'file://wechatpay/cert.pem';
    // appid 微信公众号
    public $appid = 'wx0fa00aabdd3eda40';
    // api v3 密钥
    public $v3_key = 'spxczum48btwewjmqx5w44c4vhgblmto';



    /* 
        关闭订单
        param string $out_trade_no 商户订单号
    */

    function close_pay_order($out_trade_no)
    {
        $instance = $this->create_instance();
        $resp = $instance
            ->chain('v3/pay/transactions/out-trade-no/' . $out_trade_no . '/close')
            ->post(['json' => [
                'mchid'=>$this->merchantId
            ]]);
        return json_decode($resp->getBody(), true);
    }

    /* 
        订单查询
        param string $out_trade_no 商户订单号
    */

    function get_pay_order($out_trade_no)
    {
        $instance = $this->create_instance();
        $resp = $instance
            ->chain('v3/pay/transactions/out-trade-no/' . $out_trade_no)
            ->get([
                'query'        => ['mchid' => $this->merchantId]
            ]);
        return json_decode($resp->getBody(), true);
    }


    /*
        h5下单
        param string $out_trade_no 商户订单号32位 唯一
        param string $description 商品描述
        param number $total 商品金额 分
        param string $notify_url 支付成功通知地址
        param string attach 附加数据
    */
    function h5($out_trade_no, $description, $total, $notify_url, $attach = '')
    {

        $instance = $this->create_instance();
        $resp = $instance
            ->chain('v3/pay/transactions/h5')
            ->post(['json' => [
                'mchid'        => $this->merchantId,
                'out_trade_no' => $out_trade_no,
                'appid'        => $this->appid,
                'description'  => $description,
                // 'notify_url'   => 'https://www.hikruihe.com.cn/home/index/get_wx_info',
                'notify_url' => $notify_url,
                'amount'       => [
                    'total'    => $total,
                    'currency' => 'CNY'
                ],
                'attach' => $attach,
                "scene_info" => [
                    "payer_client_ip" => get_client_ip(),
                    "h5_info" => [
                        "type" => "Wap"
                    ]
                ]
            ]]);
        return json_decode($resp->getBody(), true);
    }

    /* 
        订单号查询
        param string $out_trade_no 商户订单号
    */
    function get_order_number($out_trade_no)
    {
        $instance = $this->create_instance();
        $res = $instance
            ->v3->pay->transactions->outTradeNo->_out_trade_no_
            ->get([
                'out_trade_no' => $out_trade_no,
                'query' => [
                    'mchid' => $this->merchantId,
                ]
            ]);
        return json_decode($res->getBody(), true);
    }

    /*
        Native下单
        param string $out_trade_no 商户订单号32位 唯一
        param string $description 商品描述
        param number $total 商品金额 分
        param string $notify_url 支付成功通知地址
        param string attach 附加数据
    */
    function native($out_trade_no, $description, $total, $notify_url, $attach = '')
    {
        $instance = $this->create_instance();
        $resp = $instance
            ->chain('v3/pay/transactions/native')
            ->post(['json' => [
                'mchid'        => $this->merchantId,
                'out_trade_no' => $out_trade_no,
                'appid'        => $this->appid,
                'description'  => $description,
                // 'notify_url'   => 'https://www.hikruihe.com.cn/home/index/get_wx_info',
                'notify_url' => $notify_url,
                'amount'       => [
                    'total'    => $total,
                    'currency' => 'CNY'
                ],
                'attach' => $attach
            ]]);
        return json_decode($resp->getBody(), true);
    }

    /*
        回调解密
        param string $associatedData 附加数据包
        param string $nonceStr 加密使用的随机串初始化向量
        param number $ciphertext 加密字符
    */
    function decrypt_to_string($associatedData, $nonceStr, $ciphertext)
    {
        $ciphertext = \base64_decode($ciphertext);
        if (strlen($ciphertext) <= 16) {
            return false;
        }

        // ext-sodium (default installed on >= PHP 7.2)
        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
            return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->v3_key);
        }

        // ext-libsodium (need install libsodium-php 1.x via pecl)
        if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {
            return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->v3_key);
        }

        // openssl (PHP >= 7.1 support AEAD)
        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
            $ctext = substr($ciphertext, 0, -16);
            $authTag = substr($ciphertext, -16);

            return \openssl_decrypt(
                $ctext,
                'aes-256-gcm',
                $this->v3_key,
                \OPENSSL_RAW_DATA,
                $nonceStr,
                $authTag,
                $associatedData
            );
        }
        throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
    }

    // 创建支付实例
    function create_instance()
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformPublicKeyInstance = Rsa::from($this->platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->platformCertificateFilePath);
        // 构造一个 APIv3 客户端实例
        $instance = Builder::factory([
            'mchid'      => $this->merchantId,
            'serial'     => $this->merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs'      => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        return $instance;
    }
}
